package com.fastjars.business.spring.http;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.serializer.SerializeFilter;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.fastjars.framework.json.ToJson;
import com.fastjars.framework.pojo.Page;
import org.apache.commons.util.StringUtils;
import org.springframework.util.Assert;

import java.util.HashMap;
import java.util.Map;

/**
 * Resp
 * Response Body Ajax Content
 *
 * @author Brant Liu <br> 邮箱：<br>lbf1988@qq.com <br>日期：<br>2018/05/08
 * @version 1.0.0
 */
public class Resp<T> extends Page<T> implements ToJson {
    /**
     * 返回状态码
     */
    private final int code;
    /**
     * 消息
     */
    private final String msg;
    /**
     * 消息构建
     */
    private Map<String, Object> bodyMaps;

    /**
     * Fastjson自定义过滤器
     */
    @JSONField(serialize = false)
    private SerializeFilter[] filters = new SerializeFilter[0];

    /**
     * 导入Fastjson默认过滤器
     */
    @JSONField(serialize = false)
    private SerializerFeature[] includeFeatures = new SerializerFeature[0];

    /**
     * 移除Fastjson默认过滤器
     */
    @JSONField(serialize = false)
    private SerializerFeature[] excludeFeatures = new SerializerFeature[0];

    public Resp(RespStatus status) {
        this(status.getValue(), status.getReasonPhrase());
    }

    public Resp(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    private Resp(RespStatus status, String message, Map<String, Object> bodyMaps, Page<T> page, SerializeFilter[] filters, SerializerFeature[] includeFeatures, SerializerFeature[] excludeFeatures) {
        super(page);
        this.code = status.getValue();
        if (StringUtils.isBlank(message)) {
            this.msg = status.getReasonPhrase();
        } else {
            this.msg = message;
        }
        if (!bodyMaps.isEmpty() && null == this.bodyMaps) {
            this.bodyMaps = bodyMaps;
        }
        this.filters = filters;
        this.includeFeatures = includeFeatures;
        this.excludeFeatures = excludeFeatures;
    }

    public int getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }

    public Map<String, Object> getBody() {
        return bodyMaps;
    }

    public SerializeFilter[] getFilters() {
        return filters;
    }

    public SerializerFeature[] getIncludeFeatures() {
        return includeFeatures;
    }

    public SerializerFeature[] getExcludeFeatures() {
        return excludeFeatures;
    }

    /**
     * 根据RespStatus返回一个建造器
     *
     * @return
     */
    public static ResponseBuilder status(RespStatus status) {
        Assert.notNull(status, "RespStatus must not be null");
        return new DefaultResponseBuilder(status);
    }

    /**
     * 返回一个RespStatus.OK的建造器
     *
     * @return
     */
    public static ResponseBuilder success() {
        return status(RespStatus.OK);
    }

    /**
     * 直接构建返回Page对象
     *
     * @param page {@code com.fastjars.framework.pojo.Page}
     * @return
     * @see com.fastjars.framework.pojo.Page
     */
    public static ResponseBuilder page(Page page) {
        return success().page(page);
    }

    /**
     * 没有权限
     *
     * @return
     */
    public static ResponseBuilder unauthorized() {
        return status(RespStatus.UNAUTHORIZED);
    }

    /**
     * 系统内部错误
     *
     * @return
     */
    public static ResponseBuilder internalServerError() {
        return status(RespStatus.INTERNAL_SERVER_ERROR);
    }

    /**
     * 没有登录
     *
     * @return
     */
    public static ResponseBuilder notLogin() {
        return status(RespStatus.NOT_LOGIN);
    }

    /**
     * 账户被锁定
     *
     * @return
     */
    public static ResponseBuilder locked() {
        return status(RespStatus.LOCKED);
    }

    /**
     * 您已经被强制下线，请重新登录
     *
     * @return
     */
    public static ResponseBuilder kickOutLogin() {
        return status(RespStatus.KICK_OUT_LOGIN);
    }

    /**
     * 您已经在其他地方登录，请重新登录
     *
     * @return
     */
    public static ResponseBuilder otherLogin() {
        return status(RespStatus.OTHER_LOGIN);
    }

    /**
     * 参数有误
     *
     * @return
     */
    public static ResponseBuilder parameter() {
        return status(RespStatus.PARAMETER_ERROR);
    }

    /**
     * 业务异常
     *
     * @return
     */
    public static ResponseBuilder business() {
        return status(RespStatus.BUSINESS_ERROR);
    }

    @Override
    public String toJsonString() {
        return JSONObject.toJSONString(this,this.getFilters(),this.getIncludeFeatures());
    }

    public interface ResponseBuilder {
        ResponseBuilder msg(String message);
        /**
         * 添加keyValue
         *
         * @param key
         * @param value
         * @return
         */
        ResponseBuilder put(String key, Object value);

        /**
         * 自定义过滤器
         *
         * @param filters
         * @return
         */
        ResponseBuilder filters(SerializeFilter... filters);

        /**
         * 导入默认过滤器
         *
         * @param features
         * @return
         */
        ResponseBuilder includeFeatures(SerializerFeature... features);

        /**
         * 移除默认过滤器
         *
         * @param features
         * @return
         */
        ResponseBuilder excludeFeatures(SerializerFeature... features);

        /**
         * @see com.fastjars.framework.pojo.Page
         */
        ResponseBuilder page(Page page);

        /**
         * 构建消息
         *
         * @return
         */
        Resp build();
    }

    private static class DefaultResponseBuilder implements ResponseBuilder {
        private final RespStatus status;
        private String message;
        private Page page;
        private Map<String, Object> bodyMaps = new HashMap<>();
        private SerializeFilter[] filters = new SerializeFilter[0];
        private SerializerFeature[] includeFeatures = new SerializerFeature[0];
        private SerializerFeature[] excludeFeatures = new SerializerFeature[0];

        public DefaultResponseBuilder(RespStatus status) {
            this.status = status;
        }

        @Override
        public ResponseBuilder msg(String message) {
            this.message = message;
            return this;
        }

        @Override
        public ResponseBuilder put(String key, Object value) {
            if (this.bodyMaps.containsKey(key)) {
                throw new IllegalArgumentException("key[" + key + "] has already existed");
            }
            this.bodyMaps.put(key, value);
            return this;
        }

        @Override
        public ResponseBuilder filters(SerializeFilter... filters) {
            if (null == filters) {
                return this;
            }
            int length = this.filters.length;
            SerializeFilter[] mFilters = new SerializeFilter[length + filters.length];
            System.arraycopy(this.filters, 0, mFilters, 0, length);
            System.arraycopy(filters, 0, mFilters, length, filters.length);
            this.filters = mFilters;
            return this;
        }

        @Override
        public ResponseBuilder includeFeatures(SerializerFeature... features) {
            if (null == features) {
                return this;
            }
            int length = this.includeFeatures.length;
            SerializerFeature[] mFeature = new SerializerFeature[length + features.length];
            System.arraycopy(this.includeFeatures, 0, mFeature, 0, length);
            System.arraycopy(features, 0, mFeature, length, features.length);
            this.includeFeatures = mFeature;
            return this;
        }

        @Override
        public ResponseBuilder excludeFeatures(SerializerFeature... features) {
            if (null == features) {
                return this;
            }
            int length = this.excludeFeatures.length;
            SerializerFeature[] mFeature = new SerializerFeature[length + features.length];
            System.arraycopy(this.excludeFeatures, 0, mFeature, 0, length);
            System.arraycopy(features, 0, mFeature, length, features.length);
            this.excludeFeatures = mFeature;
            return this;
        }

        @Override
        public ResponseBuilder page(Page page) {
            this.page = page;
            return this;
        }

        @Override
        public Resp build() {
            return new Resp(this.status, this.message, this.bodyMaps, this.page, this.filters, this.includeFeatures, this.excludeFeatures);
        }
    }
}
